/*
 * Licensed to the 南京汇海交通科技有限公司
 *
 * Copyright (c) 2025.
 * All rights reserved.
 *
 * 本软件属南京汇海交通科技有限公司所有，在未获得南京汇海交通科技有限公司正式授权情况下，任何企业和个人，不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。
 */
package com.chframework.common.extend;

import com.chframework.common.constant.ApplicationConstant;
import com.chframework.common.exception.SystemMessageException;
import com.chframework.common.exception.UtilityException;
import com.chframework.common.thread.threadlocal.TTLRequestContextHolder;
import com.chframework.common.thread.threadlocal.TransmittableThreadLocalHelper;
import com.chframework.common.web.IApiResult;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.time.LocalDateTime;
import java.util.Objects;

public class ServletHelper {

    /**
     * 在运行时获取当前web请求的HttpServletRequest对象
     */
    public static HttpServletRequest getRequest() throws UtilityException {
        try {
            RequestAttributes requestAttributes = TTLRequestContextHolder.getPoolThreadContext();
            if (requestAttributes == null) {
                requestAttributes = RequestContextHolder.getRequestAttributes();
            }

            if (requestAttributes == null) {
                throw new SystemMessageException(errorResult());
            }

            if (requestAttributes instanceof ServletRequestAttributes) {
                ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
                return servletRequestAttributes.getRequest();
            }

            throw new SystemMessageException(errorResult());
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * 在运行时获取当前web请求的HttpServletResponse对象
     */
    public static HttpServletResponse getResponse() throws UtilityException {
        try {
            RequestAttributes requestAttributes = TTLRequestContextHolder.getPoolThreadContext();
            if (Objects.isNull(requestAttributes)) {
                requestAttributes = RequestContextHolder.getRequestAttributes();
            }

            if (requestAttributes == null) {
                throw new SystemMessageException(errorResult());
            }

            if (requestAttributes instanceof ServletRequestAttributes) {
                ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
                return servletRequestAttributes.getResponse();
            }

            throw new SystemMessageException(errorResult());
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * 允许所有的子线程继承Session【不适用于线程池场景】
     * <p>
     * 使用场景：(1) 使用子线程、线程池异步处理HTTP请求，或者 应用Servlet异步请求 时，
     * 如果需要在子线程中获取到 HttpServletRequest 或 HttpServletRequest对象，
     * 则需使用 RequestContextHolder 中的 inheritableRequestAttributesHolder 这个容器。
     */
    public static void exposeRequestAttributes() {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        if (requestAttributes != null) {
            // 直接放弃使用RequestContextHolder对象【不适用于线程池场景】
            // RequestContextHolder.setRequestAttributes(requestAttributes, true);

            // 使用自定义的TTLRequestContextHolder对象【适配线程池场景】
            TTLRequestContextHolder.setPoolThreadContext(requestAttributes);
        }
    }

    /**
     * 因代码层次结构的规划问题，无法将com.chframework.boot.web.response.result.ApiResult移动到模块tpjk-framework-utility之中，
     * 在整个tpjk-framework-project工程中，此处特殊情况特殊处理。
     * 或者，直接在当前工具类中直接抛出RuntimeException异常也可以的。
     */
    private static IApiResult<Boolean> errorResult() {
        return new IApiResult<Boolean>() {
            private String code = "FW0900";
            private String message = "No thread-bound request found: Are you referring to request attributes outside of an actual web request, "
                    + "or processing a request outside of the originally receiving thread? "
                    + "If you are actually operating within a web request and still receive this message, "
                    + "your code is probably running outside of DispatcherServlet: In this case, "
                    + "use RequestContextListener or RequestContextFilter to expose the current request.";
            private Boolean success = false;
            private Boolean result = false;
            private LocalDateTime timestamp = LocalDateTime.now();

            @Override
            public String getRequestId() {
                return TransmittableThreadLocalHelper.getEnvironment().get(ApplicationConstant.RESPONSE_IDENTITY);
            }

            @Override
            public String getCode() {
                return this.code;
            }

            @Override
            public String getMessage() {
                return this.message;
            }

            @Override
            public Boolean getSuccess() {
                return this.success;
            }

            @Override
            public Boolean getResult() throws CloneNotSupportedException {
                return this.result;
            }

            @Override
            public LocalDateTime getTimestamp() {
                return this.timestamp;
            }
        };
    }

}
